/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.jfonia.model;

import java.util.HashMap;
import java.util.List;
import org.jfonia.connect5.basics.BasicValueNode;
import org.jfonia.connect5.basics.MutableValueNode;
import org.jfonia.connect5.intervals.Interval;
import org.jfonia.connect5.intervals.ListObserver;
import org.jfonia.connect5.relations.MergeRelation;
import org.jfonia.connect5.relations.MergeRelationInt;
import org.jfonia.model.elements.MusicalElement;
import org.jfonia.model.elements.Tone;
import org.jfonia.model.relations.ExclusiveFalseRelation;
import org.jfonia.model.relations.MergePerformanceRelation;
import org.jfonia.model.relations.TicksToTimeRelation;
import percussiongenerator.model.Pair;

/**
 *
 * @author Jannes Plyson
 */
/*deprecated
public class SequenceOld<T extends MusicalElement> extends SequenceObservable implements ISequence, ListObserver{
    private NotationSequence<T> notationSequence;
    private PerformanceSequence performanceSequence;
    private MutableValueNode<Boolean> lockPerformance;//used for conversion between ticks and nano
    private MutableValueNode<Boolean> lockNotation;  //used for conversion between ticks and nano
    private HashMap<Tone,TicksToTimeRelation> ticksToNanoRelations;    
    private Class templateClass;
    private boolean notCloning;

    public SequenceOld(Class<T> templateClass){
        this.templateClass = templateClass;
        notCloning = true;
        notationSequence = new NotationSequence<T>();
        notationSequence.addObserver(this);
        if(templateClass == Tone.class){
            performanceSequence = new PerformanceSequence();
            performanceSequence.addObserver(this);
        }else{
            performanceSequence = null;
        }
        lockNotation = new BasicValueNode<Boolean>(true);
        lockPerformance = new BasicValueNode<Boolean>(true);
        new ExclusiveFalseRelation(lockPerformance, lockNotation);
        ticksToNanoRelations = new HashMap<Tone, TicksToTimeRelation>();
    }

    //Auxiliary methods for common interface ISequence (used by CommandStack)
    public MusicalElement getMusicalElement(int tick) {
        return getNodeFromValue(tick);
    }

    public MusicalElement addMusicalElement(MusicalElement musicalElement) {
        add(musicalElement);
        return musicalElement;
    }

    public MusicalElement insertMusicalElement(int beginTick, MusicalElement musicalElement) {
        if(beginTick > getNotationLength())
        {
                add(musicalElement);
                return musicalElement;
        }
        MusicalElement previousElement = getNodeFromValue(beginTick);
        if(previousElement == null || previousElement.getEnd() == beginTick)
                add(musicalElement);
        else
        {
                insert(indexOf(previousElement), musicalElement);
        }
        return musicalElement;
    }

    public void addMusicalElements(List<MusicalElement> musicalElements)
    {
            for(MusicalElement musicalElement : musicalElements)
                    addMusicalElement(musicalElement);
    }

    public void insertMusicalElements(int beginTick, List<MusicalElement> musicalElements)
    {
            int tickPosition = beginTick;
            for(MusicalElement musicalElement : musicalElements)
            {
                    insertMusicalElement(tickPosition, musicalElement);
                    tickPosition += musicalElement.getDifference();
            }
    }

    public void removeMusicalElement(MusicalElement musicalElement) {
        int index = indexOf(musicalElement);
        if(index >= 0)
                remove(index);
    }

    public int getMusicalLength() {
        return getNotationLength();
    }
    //End auxiliary methods

    public Pair<MusicalElement,PerformanceNode> add(MusicalElement musicalElement){
        notationSequence.add(musicalElement);
        //intervaladded will add a performance node to;
        PerformanceNode performanceNode = null;
        if(performanceSequence != null){
            performanceNode = (PerformanceNode)performanceSequence.getIntervalFromIndex(0);
        }
        return new Pair<MusicalElement,PerformanceNode>(musicalElement,performanceNode);                     
    }

    public Pair<MusicalElement,PerformanceNode> add(PerformanceNode performanceNode){
        if(performanceSequence != null){
            performanceSequence.add(performanceNode);
            //intervaladded will add a notation node to;
            MusicalElement musicalElement = (MusicalElement)notationSequence.getIntervalFromIndex(0);
            return new Pair<MusicalElement, PerformanceNode>(musicalElement, performanceNode);
        }        
        return null;
    }

    
    public Pair<MusicalElement,PerformanceNode> add(MusicalElement musicalElement,PerformanceNode performanceNode){
        notCloning = false;
        Pair<MusicalElement, PerformanceNode> pair = new Pair<MusicalElement, PerformanceNode>(musicalElement, null);
        notationSequence.add(musicalElement);
        if(performanceSequence != null){
            performanceSequence.add(performanceNode);            
            pair = new Pair<MusicalElement, PerformanceNode>(musicalElement, performanceNode);
        }
        notCloning = true;
        return pair;
    }

    public Pair<MusicalElement,PerformanceNode> insert(int pos,MusicalElement musicalElement,PerformanceNode performanceNode){
        notCloning = false;
        Pair<MusicalElement, PerformanceNode> pair = new Pair<MusicalElement, PerformanceNode>(musicalElement, null);
        notationSequence.insert(pos,musicalElement);
        if(performanceSequence != null){
            performanceSequence.insert(pos,performanceNode);            
            pair = new Pair<MusicalElement, PerformanceNode>(musicalElement, performanceNode);
        }
        notCloning = true;
        return pair;
    }

    public Pair<MusicalElement,PerformanceNode> insert(int position, MusicalElement musicalElement){
        notationSequence.insert(position, musicalElement);
        //intervaladded will add a performance node to;
        PerformanceNode performanceNode = null;
        if(performanceSequence != null){
            performanceNode = (PerformanceNode)performanceSequence.getIntervalFromIndex(position);
        }
        return new Pair<MusicalElement,PerformanceNode>(musicalElement,performanceNode);                         
    }    
    
    public Pair<MusicalElement,PerformanceNode> insert(int position, PerformanceNode performanceNode){
        if(performanceSequence != null){            
            performanceSequence.insert(position, performanceNode);
            //intervaladded will add a notation node to;
            MusicalElement musicalElement = (MusicalElement)notationSequence.getIntervalFromIndex(position);
            return new Pair<MusicalElement, PerformanceNode>(musicalElement, performanceNode);
        }            
        return null;
    }

    public Pair<MusicalElement,PerformanceNode> getNodeFromIndex(int index){
        MusicalElement sn = (MusicalElement)notationSequence.getIntervalFromIndex(index);
        PerformanceNode pn = null;
        if(performanceSequence != null)
                pn = (PerformanceNode)performanceSequence.getIntervalFromIndex(index);
        return new Pair<MusicalElement,PerformanceNode>(sn,pn);
    }

    public MusicalElement getNodeFromValue(int ticks){
        return (MusicalElement)notationSequence.getIntervalFromValue(ticks);
    }

    public PerformanceNode getNodeFromValue(long nanoTime){
        return (PerformanceNode)performanceSequence.getIntervalFromValue(nanoTime);
    }

    public int indexOf(MusicalElement MusicalElement){
        return notationSequence.indexOf(MusicalElement);
    }

    public int indexOf(PerformanceNode performanceNode){
        return performanceSequence.indexOf(performanceNode);
    }   

    public NotationSequence<T> getNotationSequence(){
        return notationSequence;
    }

    public PerformanceSequence getPerformanceSequence(){
        return performanceSequence;
    }

    public int getNotationLength(){
        return notationSequence.getDifference();
    }

    public long getPerformanceLength(){
        return performanceSequence.getDifference();
    }

    public int getSize(){
        return notationSequence.size();
    }

    public void setLockPerformance(boolean lock){
        lockPerformance.setValue(lock);
    }

    public boolean getLockPerformance(){
        return lockPerformance.getValue();
    }

    public MutableValueNode<Boolean> getLockPerformanceNode(){
        return lockPerformance;
    }

    public void setLockNotation(boolean lock){
        lockNotation.setValue(lock);
    }

    public boolean getLockNotation(){
        return lockNotation.getValue();
    }

    public MutableValueNode<Boolean> getLockMusicalElement(){
        return lockNotation;
    }

    public void remove(int index){
        MusicalElement notNode = (MusicalElement)notationSequence.getIntervalFromIndex(index);
        notationSequence.remove(index);        
    }

    public Class getTemplateClass(){
        return templateClass;
    }

    private Pair<MusicalElement,PerformanceNode> getPair(Interval interval){
        MusicalElement musicalElement;
        PerformanceNode performanceNode = null;
        if(interval.getBegin() instanceof Integer){
            musicalElement = (MusicalElement)interval;
            if(performanceSequence != null){
                performanceNode = (PerformanceNode)performanceSequence.getIntervalFromIndex(notationSequence.indexOf(interval));
            }
        }else{
            performanceNode = (PerformanceNode)interval;
            musicalElement = (MusicalElement)notationSequence.getIntervalFromIndex(performanceSequence.indexOf(interval));
        }
        return new Pair<MusicalElement,PerformanceNode>(musicalElement,performanceNode);        
    }

    public void shift(long shiftLength){
        lockPerformance.setValue(true);
        lockNotation.setValue(true);//lowers overhead
        if(performanceSequence != null){
            shiftLength %= performanceSequence.getDifference();
            long newEnd = performanceSequence.getDifference()-shiftLength;
            PerformanceNode perNode = (PerformanceNode)performanceSequence.getIntervalFromValue(newEnd);            
            int startIndex = indexOf(perNode);
            PerformanceNode perNodeNew = null;
            MusicalElement musicalElementNew = null;
            MusicalElement musicalElement = null;
            if(perNode.getBegin().longValue() != newEnd){//splitting required;
                perNodeNew = perNode.clone();
                musicalElement = ((MusicalElement)notationSequence.getIntervalFromIndex(startIndex));
                musicalElementNew = musicalElement.clone();
                musicalElement.setDifference(0);
                perNodeNew.getDifferenceNode().setValue(newEnd-perNode.getBegin());
                insert(startIndex, musicalElementNew, perNodeNew);
                perNode.setDifference(perNode.getDifference()-perNodeNew.getDifference());
                startIndex++;
            }            
            int size = getSize();
            MergeRelation.enableMerge.setValue(false);
            for(int i = startIndex; i < size; i++){
                int index = performanceSequence.size()-1;
                PerformanceNode pn = (PerformanceNode)performanceSequence.getIntervalFromIndex(index);
                MusicalElement me = (MusicalElement)notationSequence.getIntervalFromIndex(index);
                performanceSequence.remove(index);
                //intervalRemoved will remove the MusicalElement
                insert(0,me,pn);
            }            
            if(perNodeNew != null){
                new MergePerformanceRelation(perNodeNew, perNode, performanceSequence, musicalElementNew, musicalElement);
                //new MergeRelationLong(perNodeNew, perNode, performanceSequence);
                //new MergeRelationInt(musicalElementNew, musicalElement, notationSequence);
            }
        }
        lockNotation.setValue(false);
        MergeRelation.enableMerge.setValue(true);
    }

    public void shift(int shiftLength){
        lockNotation.setValue(true);
        lockPerformance.setValue(true);//lowers overhead
        shiftLength %= notationSequence.getDifference();
        int newEnd = notationSequence.getDifference()-shiftLength;
        MusicalElement musicalElement = (MusicalElement)notationSequence.getIntervalFromValue(newEnd);
        int startIndex = indexOf(musicalElement);
        MusicalElement musicalElementNew = null;
        PerformanceNode perNodeNew = null;
        PerformanceNode perNode = null;
        if(musicalElement.getBegin().longValue() != newEnd){//splitting required;
            musicalElementNew = musicalElement.clone();
            if(performanceSequence != null){
                perNode = ((PerformanceNode)performanceSequence.getIntervalFromIndex(startIndex));
                perNodeNew = perNode.clone();
                perNodeNew.setDifference(0l);
            }
            musicalElementNew.getDifferenceNode().setValue(newEnd-musicalElement.getBegin());
            insert(startIndex, musicalElementNew, perNodeNew);
            musicalElement.setDifference(musicalElement.getDifference()-musicalElementNew.getDifference());
            startIndex++;
        }
        int size = getSize();
        MergeRelation.enableMerge.setValue(false);
        for(int i = startIndex; i < size; i++){
            int index = notationSequence.size()-1;
            MusicalElement me = (MusicalElement)notationSequence.getIntervalFromIndex(index);
            PerformanceNode pn = null;
            if(performanceSequence != null){
                pn = (PerformanceNode)performanceSequence.getIntervalFromIndex(index);
            }
            notationSequence.remove(index);
            //intervalRemoved will remove the MusicalElement
            insert(0,me,pn);
        }
        if(perNodeNew != null){            
            if(performanceSequence != null){
                //new MergeRelationLong(perNodeNew, perNode, performanceSequence);
                new MergePerformanceRelation(perNodeNew, perNode, performanceSequence, musicalElementNew, musicalElement);
            }else{
                new MergeRelationInt(musicalElementNew, musicalElement, notationSequence);
            }
        }        
        lockPerformance.setValue(false);
        MergeRelation.enableMerge.setValue(true);
    }

    public void intervalAdded(Interval interval) {
        if(performanceSequence == null || performanceSequence.size() == notationSequence.size()){
            nodeAdded(this, getPair(interval));
        }if(performanceSequence != null && notCloning){
            if(performanceSequence.size() < notationSequence.size()){
                PerformanceNode performanceNode = new PerformanceNode(0l);
                performanceSequence.insert(notationSequence.indexOf(interval),performanceNode);

            }else if( notationSequence.size() < performanceSequence.size()){
                try{
                    MusicalElement MusicalElement = (MusicalElement) templateClass.newInstance();
                    notationSequence.insert(performanceSequence.indexOf(interval),MusicalElement);
                }catch(Exception exc){}
            }
        }
    }

    public void intervalRemoved(Interval interval, int i) {
        if(performanceSequence == null){
            nodeRemoved(this,(MusicalElement)interval);
        }else if(performanceSequence.size() != notationSequence.size()){
            if(interval.getBegin() instanceof Integer){
                performanceSequence.remove(i);
                nodeRemoved(this,(MusicalElement)interval);
            }else{
                notationSequence.remove(i);
                nodeRemoved(this,(PerformanceNode)interval);
            }
        }
    }

    public void intervalEndChanged(Interval interval) {
        if(interval.getBegin() instanceof Integer){
            nodeDifferenceChanged(this, (MusicalElement)interval);
        }else{
            nodeDifferenceChanged(this, (PerformanceNode)interval);
        }
    }

}
*/